/**
 * 通用js方法封装处理
 * Copyright (c) 2019 ruoyi
 */

/**
 * 日期格式化
 * @param time 时间，可以是 Date 对象、字符串或数字
 * @param pattern 格式化模板，默认为 '{y}-{m}-{d} {h}:{i}:{s}'
 * @returns 格式化后的时间字符串或 null
 */
export function parseTime(time: Date | string | number, pattern?: string): string | null {
  if (arguments.length === 0 || !time) {
    return null
  }
  const format = pattern || "{y}-{m}-{d} {h}:{i}:{s}"
  let date: Date
  if (typeof time === "object") {
    date = time
  } else {
    if (typeof time === "string" && /^[0-9]+$/.test(time)) {
      time = parseInt(time)
    } else if (typeof time === "string") {
      time = time
        .replace(new RegExp(/-/gm), "/")
        .replace("T", " ")
        .replace(new RegExp(/\.[\d]{3}/gm), "")
    }
    if (typeof time === "number" && time.toString().length === 10) {
      time = time * 1000
    }
    date = new Date(time)
  }
  const formatObj: { [key: string]: number } = {
    y: date.getFullYear(),
    m: date.getMonth() + 1,
    d: date.getDate(),
    h: date.getHours(),
    i: date.getMinutes(),
    s: date.getSeconds(),
    a: date.getDay()
  }
  const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result: string, key: string) => {
    let value = formatObj[key]
    if (key === "a") {
      return ["日", "一", "二", "三", "四", "五", "六"][value]
    }
    if (result.length > 0 && value < 10) {
      value = 0 + value
    }
    return value.toString() || "0"
  })
  return time_str
}

/**
 * 表单重置（需要在 Vue 组件中使用）
 * @param refName 表单的 ref 名称
 * @param vm Vue 组件实例
 */
export function resetForm(refName: string, vm: { $refs: { [key: string]: { resetFields: () => void } } }): void {
  if (vm.$refs[refName]) {
    vm.$refs[refName].resetFields()
  }
}

/**
 * 添加日期范围到参数对象
 * @param params 参数对象
 * @param dateRange 日期范围数组
 * @param propName 属性名称前缀（可选）
 * @returns 处理后的参数对象
 */
export function addDateRange<T extends { params?: { [key: string]: any } }>(
  params: T,
  dateRange: [string, string] | [],
  propName?: string
): T {
  const search = params
  search.params =
    typeof search.params === "object" && search.params !== null && !Array.isArray(search.params) ? search.params : {}
  dateRange = Array.isArray(dateRange) ? dateRange : []
  if (typeof propName === "undefined") {
    search.params["beginTime"] = dateRange[0]
    search.params["endTime"] = dateRange[1]
  } else {
    search.params["begin" + propName] = dateRange[0]
    search.params["end" + propName] = dateRange[1]
  }
  return search
}

/**
 * 回显数据字典
 * @param datas 数据字典数组
 * @param value 值
 * @returns 对应的标签或原始值
 */
export function selectDictLabel(datas: { value: string; label: string }[], value?: string): string {
  if (value === undefined) {
    return ""
  }
  const actions: string[] = []
  datas.some((data) => {
    if (data.value === value) {
      actions.push(data.label)
      return true
    }
    return false
  })
  if (actions.length === 0) {
    actions.push(value)
  }
  return actions.join("")
}

/**
 * 回显数据字典（字符串数组）
 * @param datas 数据字典数组
 * @param value 值（字符串或数组）
 * @param separator 分隔符，默认为 ','
 * @returns 格式化后的标签字符串
 */
export function selectDictLabels(
  datas: { value: string; label: string }[],
  value?: string | string[],
  separator?: string
): string {
  if (value === undefined || (typeof value !== "string" && !Array.isArray(value))) {
    return ""
  }
  if (Array.isArray(value) && value.length === 0) {
    return ""
  }
  const currentSeparator = separator === undefined ? "," : separator
  const values = Array.isArray(value) ? value.join(",") : value
  const actions: string[] = []
  const temp = values.split(currentSeparator)

  temp.forEach((val) => {
    let match = false
    datas.some((data) => {
      if (data.value === val) {
        actions.push(data.label + currentSeparator)
        match = true
        return true
      }
      return false
    })
    if (!match) {
      actions.push(val + currentSeparator)
    }
  })
  return actions.join("").substring(0, actions.join("").length - 1)
}

/**
 * 字符串格式化 (%s)
 * @param str 包含 %s 的字符串
 * @param args 替换参数
 * @returns 格式化后的字符串
 */
export function sprintf(str: string, ...args: any[]): string {
  let i = 0
  const result = str.replace(/%s/g, () => {
    const arg = args[i++]
    if (typeof arg === "undefined") {
      return ""
    }
    return arg.toString()
  })
  return result
}

/**
 * 转换字符串，undefined/null 转化为 ""
 * @param str 输入字符串
 * @returns 处理后的字符串
 */
export function parseStrEmpty(str: any): string {
  if (!str || str === "undefined" || str === "null") {
    return ""
  }
  return str.toString()
}

/**
 * 数据合并
 * @param source 源对象
 * @param target 目标对象
 * @returns 合并后的对象
 */
export function mergeRecursive<T extends U, U extends object>(source: T, target: U): T {
  for (const p in target) {
    if (Object.prototype.hasOwnProperty.call(target, p)) {
      try {
        if (target[p] && typeof target[p] === "object" && !Array.isArray(target[p])) {
          source[p] = mergeRecursive(source[p] || {}, target[p] as any) as any
        } else {
          source[p] = target[p] as any
        }
      } catch (e) {
        source[p] = target[p] as any
      }
    }
  }
  return source
}

/**
 * 构造树型结构数据
 * @param data 数据源
 * @param id id字段，默认 'id'
 * @param parentId 父节点字段，默认 'parentId'
 * @param children 孩子节点字段，默认 'children'
 * @returns 树形结构数据
 */
interface TreeNode {
  [key: string]: any
  id: string | number
  parentId: string | number
  children?: TreeNode[]
}

interface Config {
  id: keyof TreeNode
  parentId: keyof TreeNode
  childrenList: keyof TreeNode
}

export function handleTree(data: TreeNode[], id?: string, parentId?: string, children?: string): TreeNode[] {
  const config: Config = {
    id: id || "id",
    parentId: parentId || "parentId",
    childrenList: children || "children"
  }

  const childrenListMap: { [key: string | number]: TreeNode[] } = {}
  const nodeIds: { [key: string | number]: TreeNode } = {}
  const tree: TreeNode[] = []

  for (const d of data) {
    const parentIdValue = d[config.parentId] // 使用 config.parentId
    if (!childrenListMap[parentIdValue]) {
      childrenListMap[parentIdValue] = []
    }
    nodeIds[d[config.id]] = d // 使用 config.id
    childrenListMap[parentIdValue].push(d)
  }

  for (const d of data) {
    const parentIdValue = d[config.parentId] // 使用 config.parentId
    if (!nodeIds[parentIdValue]) {
      tree.push(d)
    }
  }

  const adaptToChildrenList = (o: TreeNode) => {
    if (childrenListMap[o[config.id]]) {
      // 使用 config.id
      o[config.childrenList] = childrenListMap[o[config.id]] // 使用 config.childrenList
    }
    if (o[config.childrenList]) {
      for (const c of o[config.childrenList]) {
        adaptToChildrenList(c)
      }
    }
  }

  for (const t of tree) {
    adaptToChildrenList(t)
  }

  return tree
}
/**
 * 参数处理
 * @param params 参数对象
 * @returns 序列化后的参数字符串
 */
export function tansParams(params: { [key: string]: any }): string {
  let result = ""
  for (const propName of Object.keys(params)) {
    const value = params[propName]
    const part = encodeURIComponent(propName) + "="
    if (value !== null && value !== "" && typeof value !== "undefined") {
      if (typeof value === "object") {
        for (const key of Object.keys(value)) {
          if (value[key] !== null && value[key] !== "" && typeof value[key] !== "undefined") {
            const paramsKey = `${propName}[${key}]`
            const subPart = encodeURIComponent(paramsKey) + "="
            result += subPart + encodeURIComponent(value[key]) + "&"
          }
        }
      } else {
        result += part + encodeURIComponent(value) + "&"
      }
    }
  }
  return result.slice(0, -1) // 移除末尾的 '&'
}

/**
 * 返回项目路径
 * @param p 输入路径
 * @returns 处理后的路径
 */
export function getNormalPath(p: string): string {
  if (p.length === 0 || !p || p === "undefined") {
    return p
  }
  const res = p.replace("//", "/")
  if (res[res.length - 1] === "/") {
    return res.slice(0, res.length - 1)
  }
  return res
}

/**
 * 验证是否为 blob 格式
 * @param data 数据
 * @returns 是否为 blob 格式
 */
export function blobValidate(data: { type: string }): boolean {
  return data.type !== "application/json"
}
